package org.jeecg.modules.demo.weixin.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.allinpay.sdk.util.SecretUtils;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.*;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.junit.Assert;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.interfaces.RSAPrivateKey;
import java.util.*;

public class FileUtils {

    private static final String APPID = "1549265867212906497";
    private static final String TIMESTAMP = String.valueOf(System.currentTimeMillis());
    private static final String PRIKEY = "D:\\A_work\\A_work\\code\\yunst_demo\\key\\1549265867212906497(RSA2).pfx";
    private static final String PASSWORD = "123456";
    private static final String FILEPATH = "D:\\A_work\\A_work\\download";

    public static String uploadFile(String filePath) {
        String token = "";
        try {
            File file=new File(filePath);
            InputStream is = new FileInputStream(file);
            //创建HttpClient
            CloseableHttpClient httpClient = HttpClients.createDefault();
            HttpPost httpPost = new HttpPost("http://192.168.88.143:8896/innerFile/open/uploadFile");
            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            /*绑定文件参数，传入文件流和contenttype，此处也可以继续添加其他formdata参数*/
            builder.addBinaryBody("file", is, ContentType.MULTIPART_FORM_DATA, file.getName());
            builder.addTextBody("appId", APPID);
            builder.addTextBody("timestamp", TIMESTAMP);
            //计算MD5开始
            InputStream is1 = new FileInputStream(new File(filePath));
            String md5 = getFileMD5(is1);
            builder.addTextBody("md5", md5);
            //计算MD5结束
            //加签开始
            Map<String, Object> resMap = new HashMap<>();
            resMap.put("appId", APPID);
            resMap.put("timestamp", TIMESTAMP);
            resMap.put("md5", md5);
            String source = getSignedValue(resMap);
            RSAPrivateKey privateKey = (RSAPrivateKey) SecretUtils.loadPrivateKey((String) null,
                    PRIKEY, PASSWORD);
            String sign = SecretUtils.sign(privateKey, source, "SHA256WithRSA");
            builder.addTextBody("sign", sign);
            //加签结束
            HttpEntity entity = builder.build();
            httpPost.setEntity(entity);
            //执行提交
            HttpResponse response = httpClient.execute(httpPost);
            HttpEntity responseEntity = response.getEntity();
            if (responseEntity != null) {
                //将响应的内容转换成字符串
                String result = EntityUtils.toString(responseEntity, Charset.forName("UTF-8"));
                //此处根据服务器返回的参数转换，这里返回的是JSON格式
                System.out.println(result);
                Assert.assertTrue(true);
                JSONObject resultJson = JSON.parseObject(result);
                JSONObject data = resultJson.getJSONObject("data");
                token = data.getString("token");

            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return token;
    }


//    @Test
    public static void downloadFile(String tokenStr) {
        try {
            //创建HttpClient
            CloseableHttpClient httpClient = HttpClients.createDefault();
            HttpPost httpPost = new HttpPost("http://192.168.88.143:8896/innerFile/open/uploadFile");
            List<NameValuePair> parameters = new ArrayList<NameValuePair>();
            NameValuePair appIdV = new BasicNameValuePair("appId", APPID);
            NameValuePair timestampV = new BasicNameValuePair("timestamp", TIMESTAMP);
            NameValuePair tokenV = new BasicNameValuePair("token", tokenStr);
            parameters.add(appIdV);
            parameters.add(timestampV);
            parameters.add(tokenV);
            //加签开始
            Map<String, Object> resMap = new HashMap<>();
            resMap.put("appId", APPID);
            resMap.put("timestamp", TIMESTAMP);
            resMap.put("token", tokenStr);
            String source = getSignedValue(resMap);
            RSAPrivateKey privateKey = (RSAPrivateKey) SecretUtils.loadPrivateKey((String) null,
                    PRIKEY, PASSWORD);
            String sign = SecretUtils.sign(privateKey, source, "SHA256WithRSA");
            NameValuePair signV = new BasicNameValuePair("sign", sign);
            parameters.add(signV);
            //加签结束
            UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters);
            httpPost.setEntity(formEntity);
            //执行提交
            HttpResponse response = httpClient.execute(httpPost);
            //收到返回，写文件
            HttpEntity responseEntity = response.getEntity();
            if (response.getStatusLine().getStatusCode() == 200) {
                if (responseEntity != null) {
                    InputStream is = responseEntity.getContent();
                    File file = new File(FILEPATH + getFileName(response));
                    file.getParentFile().mkdirs();
                    FileOutputStream fileout = new FileOutputStream(file);
                    /**
                     * 根据实际运行效果 设置缓冲区大小
                     */
                    byte[] buffer = new byte[1024];
                    int ch = 0;
                    while ((ch = is.read(buffer)) != -1) {
                        fileout.write(buffer, 0, ch);
                    }
                    is.close();
                    fileout.flush();
                    fileout.close();
                    Assert.assertTrue(true);
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public static String getFileMD5(InputStream in) {
        // TODO Auto-generated method stub
        if (in == null) {
            return null;
        }
        MessageDigest digest = null;
        byte buffer[] = new byte[1024];
        int len;
        try {
            digest = MessageDigest.getInstance("MD5");
            while ((len = in.read(buffer, 0, 1024)) != -1) {
                digest.update(buffer, 0, len);
            }
            in.close();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        byte[] bytes = Base64.encodeBase64(digest.digest());
        String callback = new String(bytes);
        return callback;
    }

    private static String getSignedValue(final Map<String, Object> params) {
        final Map<String, Object> copy = new TreeMap<>();
        params.forEach((k, v) -> {
            if (v != null) {
                copy.put(k, v);
            }
        });
        copy.remove("sign");
        final StringBuilder sb = new StringBuilder();
        copy.forEach((k, v) -> sb.append(k).append("=").append(v).append("&"));
        return sb.length() == 0 ? "" : sb.substring(0, sb.length() - 1);
    }

    /**
     * 获取response header中Content-Disposition中的filename值
     *
     * @param response
     * @return
     */
    public static String getFileName(HttpResponse response) {
        Header contentHeader = response.getFirstHeader("Content-Disposition");
        String filename = null;
        if (contentHeader != null) {
            HeaderElement[] values = contentHeader.getElements();
            if (values.length == 1) {
                NameValuePair param = values[0].getParameterByName("filename");
                if (param != null) {
                    try {
                        filename = param.getValue();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return filename;
    }
}
